`include "param.v"

module   vga_interface (    //1280*720
    input           clk      ,//75MHz
    input           rst_n    ,
    input   [15:0]  din      ,
    input           din_vld  ,
    input           key1     ,
    input           key2     ,
    output          rdy      ,
    output reg [15:0]  vga_rgb  ,
    output          vga_hsync,
    output          vga_vsync
);

//状态定义
    localparam	states_1 = 1; // 开门
    localparam	states_2 = 2; // 关门

    reg			[ 1:0 ]			states_current			; // 当前状态
    reg			[ 1:0 ]			states_next			    ; // 下个状态
//信号定义

    reg     [10:0]      cnt_h       ;
    wire                add_cnt_h   ;
    wire                end_cnt_h   ;
    reg     [9:0]       cnt_v       ;
    wire                add_cnt_v   ;
    wire                end_cnt_v   ;

    reg                 h_vld       ;
    reg                 v_vld       ;
    
    reg                 hsync       ;
    reg                 vsync       ;
    reg                 rd_req      ;         

    wire                rdreq       ; 
    wire                wrreq       ; 
    wire                empty       ; 
    wire                full        ; 
    wire    [15:0]      q_out       ; 
    wire    [3:0]       usedw       ; 
    wire      [9:0]   pos_x       ;	//扫描像素点的x轴坐标， 范围0-640，所以二进制需10位
	wire      [9:0]   pos_y       ;	

    assign  en = (cnt_v >= `V_START && cnt_v < `V_END && cnt_h >= `H_START && cnt_h < `H_END);
 //产生像素点坐标                
    assign pos_x = en ? (cnt_h - (`H_START - 1'b1)) : 0;
    assign pos_y = en ? (cnt_v - (`V_START - 1'b1)) : 0;

//计数器
    
    always @(posedge clk or negedge rst_n) begin 
        if (rst_n==0) begin
            cnt_h <= 0; 
        end
        else if(add_cnt_h) begin
            if(end_cnt_h)
                cnt_h <= 0; 
            else
                cnt_h <= cnt_h+1 ;
       end
    end
    assign add_cnt_h = 1;
    assign end_cnt_h = add_cnt_h  && cnt_h == `H_TP-1 ;
    
    always @(posedge clk or negedge rst_n) begin 
        if (rst_n==0) begin
            cnt_v <= 0; 
        end
        else if(add_cnt_v) begin
            if(end_cnt_v)
                cnt_v <= 0; 
            else
                cnt_v <= cnt_v+1 ;
       end
    end
    assign add_cnt_v = end_cnt_h;
    assign end_cnt_v = add_cnt_v  && cnt_v == `V_TP-1 ;

//h_vld 
    always  @(posedge clk or negedge rst_n)begin
        if(~rst_n)begin
            h_vld <= 1'b0;
        end
        else if(cnt_h == `H_START-1)begin
            h_vld <= 1'b1;
        end
        else if(cnt_h == `H_END-1)begin 
            h_vld <= 1'b0;
        end 
    end

//v_vld
    always  @(posedge clk or negedge rst_n)begin
        if(~rst_n)begin
            v_vld <= 1'b0;
        end
        else if(end_cnt_h && cnt_v == `V_START-1)begin
            v_vld <= 1'b1;
        end
        else if(end_cnt_h && cnt_v == `V_END-1)begin
            v_vld <= 1'b0;
        end
    end

//rd_req
    always  @(posedge clk or negedge rst_n)begin
        if(~rst_n)begin
            rd_req <= 1'b0;
        end
        else if(usedw <= 4)begin
            rd_req <= 1'b1;
        end
        else if(usedw >= 12)begin
            rd_req <= 1'b0;
        end
    end
//hsync
    always  @(posedge clk or negedge rst_n)begin
        if(~rst_n)begin
            hsync <= 0;
        end
        else if(add_cnt_h && cnt_h == `H_SW-1)begin
            hsync <= 1'b1;
        end
        else if(end_cnt_h/*add_cnt_h && cnt_h == `H_TP-1*/)begin 
            hsync <= 1'b0;
        end     
    end
//vsync
    always  @(posedge clk or negedge rst_n)begin
        if(~rst_n)begin
            vsync <= 1'b0;
        end
        else if(add_cnt_v && cnt_v == `V_SW-1)begin
            vsync <= 1'b1;
        end
        else if(end_cnt_v/*add_cnt_v && cnt_v == `V_TP-1*/)begin
            vsync <= 1'b0;
        end
    end

//FIFO例化
    vga_buf u_buf(
	.aclr       (~rst_n     ),
	.clock      (clk        ),
	.data       (din        ),
	.rdreq      (rdreq      ),
	.wrreq      (wrreq      ),
	.empty      (empty      ),
	.full       (full       ),
	.q          (q_out      ),
	.usedw      (usedw      )
    );

    
    // always @(*)begin
    //     if(pos_x[9:4] >=15 && pos_x[9:4] < 25 && pos_y[9:4] >= 8 && pos_y[9:4] < 10&& char[char_y][159-char_x] == 1'b1) begin
	// 			vga_rgb = (h_vld & v_vld)? `WHITE:0;
    //     end
    //     else begin
    //         vga_rgb = (h_vld & v_vld)?q_out:0;
    //     end
    // end

    assign wrreq = ~full && din_vld;
    assign rdreq = ~empty && h_vld && v_vld;

//输出
    assign rdy = rd_req;
    assign vga_hsync = hsync;
    assign vga_vsync = vsync;


//*******************************************************************
//--按钮控制门开关
//*******************************************************************    

//状态转移
    always @( posedge clk or negedge rst_n ) begin
        if ( !rst_n ) begin
            states_current <= states_1;
        end
        else begin
            states_current <= states_next;
        end
    end
    //状态判断
    always @( posedge clk or negedge rst_n ) begin
        if ( !rst_n ) begin
            states_next <= states_1;
        end
        else if ( key1 ) begin
            states_next <= states_1;
        end
        else if ( key2 ) begin
            states_next <= states_2;
        end
        else begin
            states_next <= states_next;
        end
    end

    always @(*)begin
        case(states_current)
        //显示关门
            states_1 : begin
                if(pos_x[9:4] >=15 && pos_x[9:4] < 25 && pos_y[9:4] >= 8 && pos_y[9:4] < 10&& char[char_y][159-char_x] == 1'b1) begin
				    vga_rgb = (h_vld & v_vld)? `WHITE:0;
                end
                else begin
                    vga_rgb = (h_vld & v_vld)?q_out:0;
                end
            end
        //显示开门
            states_2 : begin
                if(pos_x[9:4] >=15 && pos_x[9:4] < 25 && pos_y[9:4] >= 8 && pos_y[9:4] < 10&& char[char_y][159-char_x] == 1'b1) begin
				    vga_rgb = (h_vld & v_vld)? `WHITE:0;
                end
                else begin
                    vga_rgb = (h_vld & v_vld)?q_out:0;
                end
            end
        endcase
    end

//*******************************************************************
//--char字符显示
//*******************************************************************    
    
    
    wire    [9:0]   char_x  ;   //字符显示X轴坐标
    wire    [9:0]   char_y  ;   //字符显示Y轴坐标
    reg     [159:0] char    [31:0]  ;   //字符宽160 ，高32
    assign  char_x  =   (pos_x[9:4] >=15 && pos_x[9:4] < 25 && pos_y[9:4] >= 8 && pos_y[9:4] < 10)? (pos_x - 15*16) : 0;
    assign  char_y  =   (pos_x[9:4] >=15 && pos_x[9:4] < 25 && pos_y[9:4] >= 8 && pos_y[9:4] < 10)? (pos_y - 8*16) : 0;
    //字符“请选择难度”
    always@(posedge clk)
    begin
        case(states_current)
            states_1:begin
                char[0]      =  160'h0000000000000000000000000000000000000000; 
                char[1]      =  160'h0000000000000000000000000000000000000000; 
                char[2]      =  160'h0000000000020000010000000000080001000000;
                char[3]      =  160'h0c0800800003800000c0000000600e0000c00000;
                char[4]      =  160'h060fffc0000180000060002000300e0000e00010;
                char[5]      =  160'h030c0080000080000071fff000180c000067fff8;
                char[6]      =  160'h030c00800400801000300060001c18000c604030;
                char[7]      =  160'h002c008007fffff804200060000c10000e006030;
                char[8]      =  160'h004c00800c00003007000060000c30000c007030;
                char[9]      =  160'h004fff800c00006006000060000020300c006030;
                char[10]     <=  160'h004c00801c000140060000600ffffff80c006030;
                char[11]     <=  160'h304c008003ffff8006000060000180000c006130;
                char[12]     <=  160'h188c00800007000006000060000180000cfffff0;
                char[13]     <=  160'h0c8c0080000c080006000060000180000c00e030;
                char[14]     <=  160'h088fff800018060006000060000180000c01e030;
                char[15]     <=  160'h010c00800030030006000060000180000c016030;
                char[16]     <=  160'h010800000040018006000060000180180c036030;
                char[17]     <=  160'h0100000001ffffc0060000603ffffffc0c066030;
                char[18]     <=  160'h0320002001fe00c006000060000340000c046030;
                char[19]     <=  160'h023ffff00081008006000060000320000c086030;
                char[20]     <=  160'h02318c600001c00006000060000320000c106030;
                char[21]     <=  160'h06318c600001800006000060000610000c206030;
                char[22]     <=  160'h3e318c600001818006000060000c18000c406030;
                char[23]     <=  160'h0e318c6003ffffc006000060000c08000d806030;
                char[24]     <=  160'h0c318c60000180000600006000180c000c046030;
                char[25]     <=  160'h0c318c600001800006000060003007000c03e030;
                char[26]     <=  160'h0c318c600001800006000060006003800c00c030;
                char[27]     <=  160'h0c318c600001800006000c60018001e00c008030;
                char[28]     <=  160'h0c318c6c00018018060003e0030000fc0c0003f0;
                char[29]     <=  160'h0dfffffc3ffffffc060000e00c0000380c0000f0;
                char[30]     <=  160'h0000000000000000040000c03000000008000060;
                char[31]     <=  160'h0000000000000000000000000000000000000000;                                               
            end
            states_2:begin
                char[0]      <=  160'h0000000000000000000000000000000000000000;
                char[1]      <=  160'h0000000000000000000000000000000000000000;
                char[2]      <=  160'h0000000000020000010000000080000000000000;
                char[3]      <=  160'h0c0800800003800000c0000000c0000000000020;
                char[4]      <=  160'h060fffc0000180000060002000c0000000000070;
                char[5]      <=  160'h030c0080000080000071fff000c000181ffffff8;
                char[6]      <=  160'h030c0080040080100030006000c3fffc00300c00;
                char[7]      <=  160'h002c008007fffff80420006000c0060000300c00;
                char[8]      <=  160'h004c00800c0000300700006000cc060000300c00;
                char[9]      <=  160'h004fff800c000060060000603ffe060000300c00;
                char[10]      <=  160'h004c00801c0001400600006000c0060000300c00;
                char[11]      <=  160'h304c008003ffff800600006000c0060000300c00;
                char[12]      <=  160'h188c0080000700000600006000c0060000300c00;
                char[13]      <=  160'h0c8c0080000c08000600006000c0060000300c00;
                char[14]      <=  160'h088fff80001806000600006000cc060000300c18;
                char[15]      <=  160'h010c0080003003000600006000f006003ffffffc;
                char[16]      <=  160'h01080000004001800600006001c0060000300c00;
                char[17]      <=  160'h0100000001ffffc0060000600fc0060000300c00;
                char[18]      <=  160'h0320002001fe00c0060000603cc0060000300c00;
                char[19]      <=  160'h023ffff0008100800600006010c0060000300c00;
                char[20]      <=  160'h02318c600001c0000600006000c0060000300c00;
                char[21]      <=  160'h06318c60000180000600006000c0060000200c00;
                char[22]      <=  160'h3e318c60000181800600006000c0060000600c00;
                char[23]      <=  160'h0e318c6003ffffc00600006000c0060000600c00;
                char[24]      <=  160'h0c318c60000180000600006000c0060000c00c00;
                char[25]      <=  160'h0c318c60000180000600006000c0060000800c00;
                char[26]      <=  160'h0c318c60000180000600006000c0060001000c00;
                char[27]      <=  160'h0c318c600001800006000c6010c0460002000c00;
                char[28]      <=  160'h0c318c6c00018018060003e00fc03e0004000c00;
                char[29]      <=  160'h0dfffffc3ffffffc060000e003800e0018000c00;
                char[30]      <=  160'h0000000000000000040000c00100080020000800;
                char[31]      <=  160'h0000000000000000000000000000000000000000; 
            end
        endcase
        
    end

endmodule 

